/*
 * @Author: yangzonglong
 * @Date: 2021-02-22 13:59:06
 * @version: v1.0.0
 * @Descripttion:
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2023-11-26 21:34:41
 * @Auditor:
 */
import React, { useCallback, useEffect, useMemo } from 'react';
import { useDrop, DropTargetMonitor } from 'react-dnd';
import classname from 'classnames';
import useFdStore from './../../../../hooks/useFdStore';
import { ActionTypes } from './../../../../reducer';
import CanvasItem from './CanvasItem';
import CanvasItemActions from './CanvasItemActions';
import { ControlProps } from './../../../../interface';
import { createRandomStr, createControlDefOptions, flatControl, controlToTree } from './../../../../util';
import { ControlType, dragSourceMap } from './../../../../config';
import style from './../../../design.module.scss';
interface DragItemProps {
  type: string;
  index: number;
  data: ControlProps;
}

function handControlOptions(options: ControlProps['options']) {
  return options?.formItemProps?.name ? {
    ...options,
    formItemProps: {
      ...options?.formItemProps,
      name: Math.random().toString(36).substring(2)
    }
  } : (options?.name ? {
    ...options,
    name: Math.random().toString(36).substring(2)
  } : options);
}

let listLength = 0;
const baseAccept = Object.values(ControlType).map(item => 'add_' + item);

const Canvas = () => {
  const { dispatch, state } = useFdStore();
  const { dragDirection, dragSource, hoverControlId, list, curControl, tableCurrentController, dataListCurrentController, modelListAndModelName } = state;

  useEffect(() => {
    //数量变化的时候给最后一个加选中
    if (list.length !== listLength && list.length) {
      listLength = list.length;
      let _curControl = list[list.length - 1];

      dispatch({
        type: ActionTypes.CHANGE_CONTROL,
        curControl: _curControl,
      });
      // 表格有二级设置页面 需要清除
      if (_curControl.type === 'table') {
        tableCurrentController?.fn?.({});
      }
      if (_curControl.type === 'dataList') {
        dataListCurrentController?.fn?.({});
      }
    }
  }, [dataListCurrentController, dispatch, list, tableCurrentController]);

  const flatList = useMemo(() => {
    return flatControl(list)
  }, [list]);

  const [collect, drop] = useDrop({
    accept: baseAccept.concat(flatList.map(item => item.id)),
    collect: (minoter: DropTargetMonitor) => ({
      isOver: minoter.isOver({ shallow: true }),
      canDrop: minoter.canDrop(),
    })
  });

  const removeControl = useCallback(() => {
    let _list: ControlProps[] = flatList.filter(item => item.id !== curControl?.id);

    if (curControl?.type === ControlType.DATALINK) {
      let name = curControl?.['options']?.['formItemProps']?.['name'];

      _list = _list.map(item => {
        if (item.type === 'input' && item?.options?.inputProps?.bindName === name) {
          return {
            ...item,
            options: {
              ...item.options,
              inputProps: {
                ...item?.options?.inputProps,
                bindName: undefined,
                showFiled: undefined
              }
            }
          };
        } else if (item.type === 'dataLinkComBox' && item?.options?.inputProps?.bindName === name) {
          return {
            ...item,
            options: {
              ...item.options,
              inputProps: {
                ...item?.options?.inputProps,
                bindName: undefined,
                screenConditionRules: []
              }
            }
          };
        } else {
          return item;
        }
      });
    }

    dispatch({
      type: ActionTypes.SYNC_LIST,
      modelListAndModelName,
      list: controlToTree(_list),
      curControl: {} as any,
    });
  }, [list, curControl, dispatch, modelListAndModelName]);

  const copyControl = useCallback(() => {
    const addArr: ControlProps[] = [{
      ...curControl,
      id: createRandomStr(curControl!.type),
      type: curControl!.type,
      options: handControlOptions(curControl?.options)
    }];

    const each = (id: string, newId: string) => {
      flatList.forEach(item => {
        // 找到子级
        if (item.parentId === id) {
          const _id = createRandomStr(item.type);

          addArr.push({
            ...item,
            id: _id,
            parentId: newId,
            options: handControlOptions(item?.options)
          });

          each(item.id, _id);
        }
      });
    };

    each(curControl!.id, addArr[0].id);

    dispatch({
      modelListAndModelName,
      type: ActionTypes.SYNC_LIST,
      list: controlToTree(flatList.concat(addArr)),
      curControl: {} as any,
    });
  }, [list, curControl, dispatch, modelListAndModelName]);

  const editControl = useCallback((type: string) => {
    const index = list.findIndex((item) => item.id === curControl?.id);

    const _control = createControlDefOptions(type, {
      name: curControl?.options?.formItemProps.name,
      width: curControl?.options?.formItemProps?.style.width, id: curControl?.id
    });
    let _list = [...list];

    _list.splice(index, 1, _control);

    dispatch({
      type: ActionTypes.SYNC_LIST,
      modelListAndModelName,
      list: _list,
      curControl: {} as any,
    });

  }, [curControl, dispatch, modelListAndModelName, list]);

  const moveControl = useCallback(
    (id: string, toId: string, type?: string) => {
      try {
        const index = flatList.findIndex(item => item.id === id);
        const toIndex = flatList.findIndex(item => item.id === toId);

        // 从左侧菜单拖至目前元素
        if (id.startsWith('add_')) {
          if (!flatList[toIndex].children) flatList[toIndex].children = [];
          flatList[toIndex].children!.push(createControlDefOptions(id.replace('add_', '')));

          dispatch({
            type: ActionTypes.SYNC_LIST,
            modelListAndModelName,
            list: controlToTree(flatList)
          });
          return
        }

        if (index === toIndex) return;

        let arr: ControlProps[] = [];

        if (type === 'drop' && flatList[index].parentId !== flatList[toIndex].id) {
          arr = flatList.concat();

          if (['row', 'col', 'collapse'].includes(flatList[toIndex].type)) {
            arr[index].parentId = arr[toIndex].id;
          }else { // 其他组件认为交互位置
            moveControl(id, toId)
          }
        } else {
          // 找出当前拖动项所有父级ID
          let parentId = flatList[index].parentId;
          let parentIds = [parentId];

          while (parentId) {
            parentId = flatList.find(item => item.id === parentId)?.parentId;
            parentIds.push(parentId!);
          }

          if (parentIds.includes(flatList[toIndex].id)) delete flatList[index].parentId;

          flatList.forEach((item, i) => {
            if (i === toIndex) {
              if (toIndex < index) {
                arr.push(flatList[index]);
                arr.push(flatList[toIndex]);
              } else {
                arr.push(flatList[toIndex]);
                arr.push(flatList[index]);
              }
            } else if (i === index) {
            } else {
              arr.push(item);
            }
          });
        }

        dispatch({
          type: ActionTypes.SYNC_LIST,
          modelListAndModelName,
          list: controlToTree(arr)
        });
      } catch (error) {
        console.log(error)
      }
    },
    [dispatch, modelListAndModelName, list]
  );

  const setActiveControl = useCallback(
    (control: ControlProps) => {
      tableCurrentController?.fn?.({});
      dataListCurrentController?.fn?.({});
      dispatch({
        type: ActionTypes.CHANGE_CONTROL,
        curControl: control,
      });
    },
    [dataListCurrentController, dispatch, tableCurrentController]
  );

  // 设置拖动相关信息，需延迟时间
  const setDragReducer = useCallback(
    (data: Record<string, any>) => {
      dispatch(data);
    },
    [dispatch]
  );

  const createDropAccept = (item: ControlProps) => {
    const flatList = flatControl(list);

    let flatListIds = flatList.map(item => item.id);
    let parentId = item.parentId;

    while (parentId) {
      const parent = flatList.find(item => item.id === parentId);
      flatListIds = flatListIds.filter(id => id !== parentId);
      parentId = parent?.parentId;
    }

    return flatListIds.filter(id => id !== item.id).concat(baseAccept)
  };

  const createControl = (children: ControlProps[]): any => {
    return children.map((item, index) => {
      const options = {
        index,
        item,
        moveControl,
        setActiveControl,
        setDragReducer,
        dragDirection,
        dragSource,
        hoverControlId,
        curControl,
        key: item.id,
        dropAccept: createDropAccept(item)
      };

      if (item.children) {
        return <CanvasItem {...options}>{createControl(item.children)}</CanvasItem>;
      }
      return <CanvasItem {...options} />;
    });
  };

  return (
    <div
      id="canvas"
      ref={drop}
      className={classname(style.canvas, {
        [style.form]: true,
        [style.active]: collect.canDrop && collect.isOver && dragSource === dragSourceMap.MENU,
      })}
    >
      {list.length ? createControl(list) : (
        <p className={style.noListTip}>从左侧拖拽或点击来添加字段</p>
      )}

      {curControl?.id && !dragSource && (
        <CanvasItemActions
          curControl={curControl}
          editControl={editControl}
          removeControl={removeControl}
          copyControl={copyControl} />
      )}
    </div>
  );
};

export default Canvas;
